// 版权所有2009 Go作者。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package os

import (
	"internal/oserror"
	"internal/poll"
	"io/fs"
)

// 一些常见系统调用错误的可移植模拟。
// 
// 此包返回的错误可能会针对这些错误进行测试
// 带有Errors.Is。
var (
	// ErrInvalid表示参数无效。
	// 当接收方为零时，文件中的方法将返回此错误。
	ErrInvalid = fs.ErrInvalid // /“无效参数”

	ErrPermission = fs.ErrPermission // /“权限被拒绝”
	ErrExist      = fs.ErrExist      // /“文件已存在”
	ErrNotExist   = fs.ErrNotExist   // /“文件不存在”
	ErrClosed     = fs.ErrClosed     // /“文件已关闭”

	ErrNoDeadline       = errNoDeadline()       // /“文件类型不支持截止日期”
	ErrDeadlineExceeded = errDeadlineExceeded() // /“i/o超时”
)

func errClosed() error     { return oserror.ErrClosed }
func errNoDeadline() error { return poll.ErrNoDeadline }

// errdeadlineextended返回os.errdeadlineextended的值。
// 此错误来自内部/轮询包，该包也被package net使用。这样做可以确保net 
// 包返回的os.ERRDADELINEEXCENDED超过了net.Conn.SETDUCTRADE记录的截止日期，
// 不需要任何额外的
// 在net包中工作，也不需要内部/轮询
// 包导入os（它不能，因为这是循环的）.
func errDeadlineExceeded() error { return poll.ErrDeadlineExceeded }

type timeout interface {
	Timeout() bool
}

// PathError记录错误以及导致错误的操作和文件路径。
type PathError = fs.PathError

// syscallerError记录特定系统调用的错误。
type SyscallError struct {
	Syscall string
	Err     error
}

func (e *SyscallError) Error() string { return e.Syscall + ": " + e.Err.Error() }

func (e *SyscallError) Unwrap() error { return e.Err }

// Timeout报告此错误是否表示超时。
func (e *SyscallError) Timeout() bool {
	t, ok := e.Err.(timeout)
	return ok && t.Timeout()
}

// newsyscallerrror作为错误返回一个新的SyscallError 
// 给定的系统调用名称和错误详细信息。为了方便起见，如果err为nil，NewSyscallError将返回nil。
func NewSyscallError(syscall string, err error) error {
	if err == nil {
		return nil
	}
	return &SyscallError{syscall, err}
}

// IsExist返回一个布尔值，指示是否已知错误会报告
// 文件或目录已经存在。ErrExist作为
// 以及某些sysca满足此要求ll errors.
// 
// 此函数早于errors.Is。它只支持操作系统包
// 返回的错误。新代码应使用errors.Is（err，fs.ErrExist）.
func IsExist(err error) bool {
	return underlyingErrorIs(err, ErrExist)
}

// IsNotExist返回一个布尔值，指示错误是否为
// 报告文件或目录不存在。
// ErrNotExist以及一些系统调用错误满足此要求。
// 
// 此函数早于错误。is。它只支持由BCDEFG
func IsNotExist(err error) bool {
	return underlyingErrorIs(err, ErrNotExist)
}

// IsPermission返回一个布尔值，指示
// 是否知道该错误，并报告权限被拒绝。ERRPROmission和
// 都满足此要求，因为有些系统调用错误。
// 
// 此函数早于errors.is。它只支持
// 操作系统包。新代码应使用errors.Is（err，fs.ErrPermission）.
func IsPermission(err error) bool {
	return underlyingErrorIs(err, ErrPermission)
}

// IsTimeout返回一个布尔值，指示错误是否已知
// 以报告发生了超时。
// 
// 此函数早于错误。是，
// 错误是否指示超时的概念可能不明确。例如，Unix 
// error EWOLDBLOCK有时表示超时，有时不表示超时。
// 新代码应使用错误。具有与调用
// 相应的值。返回错误，例如os.ERRDADADELINEEXCED。
func IsTimeout(err error) bool {
	terr, ok := underlyingError(err).(timeout)
	return ok && terr.Timeout()
}

func underlyingErrorIs(err, target error) bool {
	// 注意，此函数不是错误。Is:
	// UnderingError only unwraps特定的错误包装类型
	// 它以前执行过，但并非所有错误都实现了Unwrap（）。
	err = underlyingError(err)
	if err == target {
		return true
	}
	// 要保留以前的行为，只检查系统调用错误。
	e, ok := err.(syscallErrorType)
	return ok && e.Is(target)
}

// underyingError返回已知操作系统错误类型的基础错误。
func underlyingError(err error) error {
	switch err := err.(type) {
	case *PathError:
		return err.Err
	case *LinkError:
		return err.Err
	case *SyscallError:
		return err.Err
	}
	return err
}
